﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VXCompany.SilverlightLogging.Services.Exceptions.LoggingSinks;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Diagnostics;
namespace VXCompany.SilverlightLogging.Services.Exceptions
{
	public class ExceptionPolicy
	{
		#region Fields
        private static object _lockMe = new object();
		private const string SVC_MOD_4 = @"System.ServiceModel 4.0.0.0";
		private const string ADDINS_FOLDER = "Bin";
		#endregion Fields

		[Import(typeof(ILoggingSink))]
		public ILoggingSink LoggingSink { get; set; }

		/// <summary>
		/// Returns the currentdirectory. (As in: web root or test folder)
		/// </summary>
		public static string CurrentFolder
		{
			get 
			{
				return System.Web.HttpContext.Current != null ? System.Web.HttpContext.Current.Server.MapPath(".") : System.Reflection.Assembly.GetEntryAssembly().CodeBase;
			}
		}

		/// <summary>
		/// Type initializer.
		/// </summary>
		private ExceptionPolicy()
		{
			Compose();
		}

		private static ExceptionPolicy _Current;
		
		/// <summary>
		/// Gets singleton ExceptionPolicy.
		/// </summary>
		public static ExceptionPolicy Current 
		{
			get
			{
				if (_Current == null)
				{
					lock (_lockMe)
					{
						if (_Current == null)
						{
							_Current = new ExceptionPolicy();
						}
					}
				}
				return _Current;
			}
		}

		#region Methods

		/// <summary>
		/// Logs provided exception
		/// </summary>
		/// <param name="ex"></param>
		/// <returns></returns>
		public bool HandleException(Exception ex)
		{           
			bool logged = false;

			try
			{
				lock (_lockMe)
				{
					logged = LoggingSink.Log(ex); 
					if (ex is ServiceException)
					{
						var svcEx = (ServiceException)ex;						
						svcEx.IsLogged = logged;
					}					
				}
			}
			catch (Exception logEx)
			{
				CreateEventLogEntryWarning(ex, logEx);
			}

			return logged;
		}

		/// <summary>
		/// Attempts to create an Eventlog entry in the application log, under an existing source, to warn administrator about this configuration error.
		/// </summary>
		/// <param name="ex"></param>
		/// <param name="logEx"></param>
		private void CreateEventLogEntryWarning(Exception ex, Exception logEx)
		{
			try
			{
				if (System.Diagnostics.EventLog.SourceExists(SVC_MOD_4))
				{
					System.Diagnostics.EventLog.WriteEntry(SVC_MOD_4, string.Format("Log Error:{0} {1} Original Error:{2}", logEx.ToString(), Environment.NewLine, ex.ToString()), System.Diagnostics.EventLogEntryType.Warning, 9999);
				}
			}
			catch
			{
 				//too bad..
			}
		}

		/// <summary>
		/// Composes ILoggingSink.
		/// </summary>
		private void Compose()
		{
			try
			{

				var catalog = new DirectoryCatalog(Path.Combine(CurrentFolder, ADDINS_FOLDER));

				var container = new CompositionContainer(catalog);

				container.ComposeParts(this);

			}

			catch (CompositionException ex)
			{
				//composition failed.  
#if DEBUG

				LoggingSink = new SessionSink();
				Trace.WriteLine("MEFcouldnotfindaloggingsink." + ex.Message);

#else  
				throw new Exception("Couldnotfindaloggingsink.",ex);  
#endif
			}
		}
		#endregion Methods
	}
}
